/**
 * 
 */
package com.istock.union.user.security.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.istock.base.common.api.model.ApiBaseResponse;
import com.istock.base.common.api.model.RetStatusEnum;
import com.istock.base.serializer.json.TypeReference;
import com.istock.union.user.client.SSOClientUtils;
import com.istock.union.user.model.SSOUser;
import com.istock.union.user.security.InnerTokenService;
import com.istock.union.user.service.AschTaskService;
import com.istock.union.user.service.impl.TokenServiceImpl;

/**
 * token是用户登录的标识
 * token主要存储在缓存里面,使用storeService实现
 * 
 * 在存储里,主要存储2种缓存
 * token:SSOUser 是主存储,用于用户登录的判断
 * tenantCode+LoginName : [token1,token2] 用于存储一个用户当前登录了多少个token,在登录的时候,如果超过一定的token数量,就会删除第一个token
 * 						验证token的过程,不会判断这个cache,只有登陆的时候,用于验证
 * 	
 * @author senvon
 *
 */
@Repository
public class InnerTokenServiceImpl extends TokenServiceImpl implements InnerTokenService {

	@Autowired
	private AschTaskService aschTaskService;
	
	/**
	 * 单个用户最大登录次数
	 * 0为不判断
	 */
	private Integer maxLoginCount = 0;
	
	/**
	 * application的超时时间,单位秒
	 * 默认值为30天
	 */
	private Long globalExpire = 60*60*24*30L;
	
	public void setMaxLoginCount(Integer maxLoginCount) {
		this.maxLoginCount = maxLoginCount;
	}

	public void setGlobalExpire(Long globalExpire) {
		this.globalExpire = globalExpire;
	}

	public ApiBaseResponse<String> generateToken(SSOUser userInfo, boolean checkLoginCount) {
		
		List<String> tokenList = findTokenList(userInfo.getTenantNo() , userInfo.getLoginName());
		if(tokenList == null) {
			tokenList = new ArrayList<String>();
		}
		
		//如果相同的一个用户,同时申请的token大于maxLoginCount
		//系统会剔除最先登录的token
		//来保证当前登录的成功
		if(checkLoginCount) {
			if(maxLoginCount > 0 && tokenList.size() >= maxLoginCount) {
				String removedToken = tokenList.get(0);
				invalidToken(removedToken);
			}
		}
		
		String token = RandomStringUtils.randomAlphanumeric(20);
		//操作token的cache部分
		userInfo.setLoginTime(new Date());
		userInfo.setToken(token);
		saveTokenModel(userInfo);
		
		if(checkLoginCount) {
			tokenList.add(token);
			saveTokenList(userInfo.getTenantNo() , userInfo.getLoginName() , tokenList);
		}
		return new ApiBaseResponse<String>(RetStatusEnum.SUCCESS, "S", "成功", token);
	}

	public List<String> findTokenList(String tenantNo , String loginName){
		String tokenKey = SSOClientUtils.USER_TOKEN_LIST + tenantNo + loginName;
		return getStorageService().getObject("" , tokenKey, new TypeReference<List<String>>() {});
	}
	
	public void saveTokenList(String tenantNo , String loginName,List<String> tokenList) {
		String tokenKey = SSOClientUtils.USER_TOKEN_LIST + tenantNo + loginName;
		getStorageService().putObject("", tokenKey, tokenList, globalExpire);
	}
	
	@Override
	public void saveTokenModel(SSOUser ssoUser) {
		if(ssoUser != null){
			String tokenKey = SSOClientUtils.KEY_TOKEN+ssoUser.getToken();
			getStorageService().putObject(ssoUser.getToken(),tokenKey, ssoUser);
		}
	}

	/**
	 * TODO
	 * @param ssoUser
	 */
	public void removeInvalidToken(String tenantNo , String loginName , String token) {
		List<String> tokenList = findTokenList(tenantNo , loginName);
		if(tokenList != null) {
			tokenList.remove(token);
			saveTokenList(tenantNo , loginName , tokenList);
		}
	}

	/** 
	 * 让某一个token失效
	 * 删除这个token所有相关的东西
	 */
	@Override
	public void invalidToken(String token) {
		String tokenKey = SSOClientUtils.KEY_TOKEN+token;
		SSOUser tokenUserModel = getStorageService().getObject(token, tokenKey, new TypeReference<SSOUser>() {});
		if(tokenUserModel != null){
			removeInvalidToken(tokenUserModel.getTenantNo() , tokenUserModel.getLoginName() , token);
			
			getStorageService().removeAll(token);
			
			//异步记录用户登出日志,取消用户在线
			aschTaskService.userOnlineRemove(new String[] {token});
		}
	}

}
